// 3-4 预处理器-# 和 ## 运算符

/**
 * C++ 预处理器
 * 预处理器是一些指令，指示编译器在实际编译之前所需完成的预处理。

 * 所有的预处理器指令都是以井号（#）开头，只有空格字符可以出现在预处理指令之前。预处理指令**不是 C++ 语句**，所以它们不会以分号（;）结尾。

 * 我们已经看到，之前所有的实例中都有 #include 指令。这个宏用于把头文件包含到源文件中。

 * C++ 还支持很多预处理指令，比如 #include、#define、#if、#else、#line 等，让我们一起看看这些重要指令。
 *
 * --------------------------------------
 * # 和 ## 运算符
 * ~~~~~~~~~~#1 start~~~~~~~~~~~~~~~~~
 * # 和 ## 预处理运算符在 C++ 和 **ANSI/ISO C** 中都是可用的。# 运算符会把 replacement-text 令牌转换为**用引号引起来的字符串**。
 * 
 * 请看下面的宏定义：（实例一 #1）
 * 当上面的代码被编译和执行时，它会产生下列结果：

    HELLO C++
 * 让我们来看看它是如何工作的。不难理解，C++ 预处理器把下面这行：

   cout << MKSTR(HELLO C++) << endl;
 
 * 转换成了：

   cout << "HELLO C++" << endl;

 * ~~~~~~~~~~#1 end~~~~~~~~~~~~~~~~~
 *
 * ~~~~~~~~~~#2 start~~~~~~~~~~~~~~~~~
 * ## 运算符用于连接两个令牌。下面是一个实例：

    #define CONCAT( x, y )  x ## y

 * 当 CONCAT 出现在程序中时，它的参数会被连接起来，并用来取代宏。例如，程序中 CONCAT(HELLO, C++) 会被替换为 "HELLO C++"，如下面实例(实例二 #2)所示。
 * 当上面的代码被编译和执行时，它会产生下列结果：

    100
 * 让我们来看看它是如何工作的。不难理解，C++ 预处理器把下面这行：

    cout << concat(x, y);
 * 转换成了：

    cout << xy;
 * ~~~~~~~~~~#2 end~~~~~~~~~~~~~~~~~
*/

#include <iostream>
#define __mark 2

/**
 * #1 实例一 预处理运算符#使用
*/
#if 1 == __mark
#define MK_STR(x) (#x)
int main(void)
{
  std::cout << MK_STR(HELLO C++) << std::endl; // "HELLO C++"

  int c = 123;
  std::cout << MK_STR(c) << std::endl; // "c"
  printf("---------------end------------------\n");
  return 0;
}
/**
 * #2 实例二 预处理运算符##使用
*/
#elif 2 == __mark
#define CONCAT(x, y) (x##y)
#define CONCAT1(x, y, z, a) (x##y##z##a)
int main(void)
{
  int xy = 100;
  int a = 1;
  int v_1C = 4;
  std::cout << CONCAT(x, y) << std::endl; //100
  // std::cout << CONCAT(++, a) << std::endl; // error: pasting "++" and "a" does not give a valid preprocessing token 粘贴“++”和“a”不会给出有效的预处理令牌
  std::cout << CONCAT1(v, _, 1, C) << std::endl;// 4
  printf("---------------end------------------\n");
  return 0;
}
#endif